package com.edu.glutdataconvertserver.config.mysql;

import com.edu.glutdataconvertcommon.common.Constants;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.util.Properties;

import static org.apache.ibatis.reflection.SystemMetaObject.DEFAULT_OBJECT_FACTORY;
import static org.apache.ibatis.reflection.SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY;

/**
 * Created by Hua wb on 2018/7/25.
 */
/*@Intercepts(value = {
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class,
                ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class,
                ResultHandler.class, CacheKey.class, BoundSql.class})}
)*/
@Intercepts({
        @Signature(method = "query", type = Executor.class, args = {
                MappedStatement.class, Object.class, RowBounds.class,
                ResultHandler.class}),
        @Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class, Integer.class}),
})
public class TableSplitInterceptor implements Interceptor {
    private static Logger logger = LoggerFactory.getLogger(TableSplitInterceptor.class);


    StrategyManager strategyManager;

    public void setStrategyManager(StrategyManager strategyManager) {
        this.strategyManager = strategyManager;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
        Object parameterObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
        doSplitTable(metaStatementHandler, parameterObject);
        // 传递给下一个拦截器处理
        return invocation.proceed();

    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }

    private void doSplitTable(MetaObject metaStatementHandler, Object param) throws ClassNotFoundException, NoSuchMethodException {
        String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
        if (originalSql != null && !originalSql.equals("")) {
            String shardingTables = MysqlConstants.SHARDING_TABLES;
            String strategyName = MysqlConstants.SHARDING_STRATEGYNAME;
            if (shardingTables != null && shardingTables.split(",").length > 0) {
                // 根据key获取策略类
                Strategy strategy = strategyManager.getStrategy(strategyName);
                try {
                    String[] split = shardingTables.split(",");
                    String convertedSql = originalSql;
                    for (String table : split) {
                        if (convertedSql.indexOf(table) > 0) {
//                            convertedSql = convertedSql.replaceAll(table + "$", strategy.returnTableName(table) + " ");
//                            convertedSql = convertedSql.replaceAll(table + " ", strategy.returnTableName(table) + " ");
                            convertedSql = convertedSql.replaceAll(table + "$", table + Constants.XQBJ + " ");
                            convertedSql = convertedSql.replaceAll(table + " ", table + Constants.XQBJ + " ");
                        }
                    }
                    metaStatementHandler.setValue("delegate.boundSql.sql", convertedSql);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
